/*
 * test_save.cpp
 *
 *  Created on: Mar 29, 2014
 *      Author: killerg
 */

#include "share/clock.h"
#include <list>
#include <map>
#include <assert.h>
#include <stdio.h>

using namespace std;

static const int MaxSavePending = 50 ;
static const int MaxSaveOpPS = 25;
static const int PLAYERNUM = 100;


enum state_t {
	NONE = 0,
	QUEING = 1,
	SAVING = 2,
};

struct playerdata_t {
	int32_t saved_stamp = -1;
	int32_t image_stamp = -1;
	int32_t change_stamp = -1;

	state_t state = NONE;
	int id;
};

static list<playerdata_t*> g_saving;
static list<playerdata_t*> g_queue;
static map<int32_t, playerdata_t*> g_players;
static my_clock_t g_clock;
static int32_t g_timeserial = 0;

void add_queue(playerdata_t* ptr, bool chged) {
	if (chged)
		ptr->change_stamp = g_timeserial++;

	if (ptr->saved_stamp >= ptr->change_stamp)
		return;

	if (ptr->state == NONE) {
		ptr->state = QUEING;
		g_queue.push_back(ptr);
	}
}

bool test_save() {
	for (int i=0; i<PLAYERNUM; ++i) {
		g_players[i] = new playerdata_t;
		g_players[i]->id = i;
	}

	if (!g_clock.init(5)) {
		return false;
	}

	while (true) {
		g_clock.begin_update();

		for (int i=0; i<100; ++i) {
			int32_t id = rand() % PLAYERNUM;
			auto ptr = g_players[id];
			add_queue(ptr, true);
		}

		// update queue
		while (!g_queue.empty() && g_saving.size() < MaxSavePending) {
			auto ptr = g_queue.front();
			g_queue.pop_front();

			assert(ptr->state == QUEING);

			if (ptr->change_stamp <= ptr->saved_stamp) {
				ptr->state = NONE;
			} else {
				ptr->state = SAVING;
				ptr->image_stamp = g_timeserial++;
				g_saving.push_back(ptr);
			}
		}

		// update save
		for (int i=0; i<MaxSaveOpPS/5 && !g_saving.empty(); ++i) {
			auto ptr = g_saving.front();
			g_saving.pop_front();

			assert(ptr->state == SAVING);
			ptr->state = NONE;

			if (rand()%100 != 0)
				ptr->saved_stamp = ptr->image_stamp;

			add_queue(ptr, false);
		}


		if (g_clock.sec_jump) {

			printf("-----------\n");
			printf("  time_serial:%d\n", g_timeserial);
			printf("  queue:%d\n", g_queue.size());
			printf("  saving:%d\n", g_saving.size());
			printf("id:%d\n", 0);
			printf("  state:%d\n", g_players[0]->state);
			printf("  change:%d\n", g_players[0]->change_stamp);
			printf("  image:%d\n", g_players[0]->image_stamp);
			printf("  saved:%d\n", g_players[0]->saved_stamp);
			printf("id:%d\n", 1);
			printf("  state:%d\n", g_players[1]->state);
			printf("  change:%d\n", g_players[1]->change_stamp);
			printf("  image:%d\n", g_players[1]->image_stamp);
			printf("  saved:%d\n", g_players[1]->saved_stamp);

			printf("-----------\n");
		}

		g_clock.end_update();
		g_clock.wait_frame();
	}

	g_clock.destroy();

	return true;
}
